/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package br.ufba.lasid.virt;

import br.ufba.lasid.base.IHost;
import br.ufba.lasid.v1.jitclouds.mda.datatypes.IMachine;
import br.ufba.lasid.v1.utils.Constants;
import br.ufba.lasid.v1.utils.ValidateIp;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.apache.commons.lang.StringUtils;
import org.libvirt.Connect;
import org.libvirt.ConnectAuth;
import org.libvirt.ConnectAuthDefault;
import org.libvirt.Domain;
import org.libvirt.LibvirtException;

/**
 *
 * @author aliriosa
 */
public class HypervisorLibVirtXen extends Xen {

    private Connect connection = null;
    private ConnectAuth defaultAuth = null;

    public HypervisorLibVirtXen() {
        this.defaultAuth = new ConnectAuthDefault();
    }

    public HypervisorLibVirtXen(String URI) {
        if (StringUtils.isEmpty(URI)) {
            System.err.println("The URI is blank. Please, set the URI before connect.");
        } else {
            this.setURI(URI);
            defaultAuth = new ConnectAuthDefault();
        }
    }

    @Override
    public void connect() {

        try {
            if (StringUtils.equalsIgnoreCase(getURI(), Constants.LOCALHOST)
                    || StringUtils.equalsIgnoreCase(getURI(), Constants.LOCALHOST_IP)) {

                this.connection = new Connect(Constants.XEN_CONNECTION, defaultAuth, 0);
                System.out.println("Localhost Encrypted connection successful!");

            } else if (ValidateIp.validate(getURI())) {
                this.connection = new Connect(Constants.XEN_SSH_CONNECTION + getURI() + Constants.BAR, defaultAuth, 0);
                System.out.println("URI: " + getURI() + " Encrypted connection successful!");
            } else {
                System.err.println("Ip or URI is not valid");
            }
        } catch (LibvirtException ex) {
            ex.getStackTrace();
        }
    }

    public void execute(String idMachine, String command) {
        try {
            this.connection.domainCreateLinux(command, 0);
        } catch (LibvirtException ex) {
            Logger.getLogger(HypervisorLibVirtXen.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void setHost(IMachine host) {
        throw new UnsupportedOperationException("Not supported yet.");
    }

    public String getDescription() throws LibvirtException {

        return getVirtualMachine().getDomainInfo();
    }

    public String getName() {
        try {
            return "Xen access by LibVirt version [" + connection.getLibVirVersion() + "]";
        } catch (LibvirtException ex) {
            ex.getStackTrace();
        }
        return null;
    }

    @Override
    public IHost getHost() {
        try {
            host.setAddress(connection.getURI());
            return host;
        } catch (LibvirtException ex) {
            Logger.getLogger(HypervisorLibVirtXen.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;
    }

    @Override
    public int disconnect() {
        try {
            return connection.close();
        } catch (LibvirtException ex) {
            ex.getStackTrace();
        }
        return 0;
    }

    @Override
    public void configureVirtualMachines() {

        try {
            setVirtualMachines(new ArrayList<VirtualMachine>());
            int[] ids;
            ids = connection.listDomains();
            for (int i : ids) {
                Domain d = connection.domainLookupByID(i);
                VirtualMachine vm = new VirtualMachine(d);
                getVirtualMachines().add(vm);
            }
        } catch (LibvirtException ex) {
            Logger.getLogger(HypervisorLibVirtXen.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    @Override
    public void setVirtualMachine(String virtualMachineID) {
        try {

            int id = Integer.parseInt(virtualMachineID);
            Domain d = this.connection.domainLookupByID(id);
            getVirtualMachine().setDomain(d);
            getVirtualMachine().getConfiguration().set(Constants.OSTypeParameter, d.getOSType());
            getVirtualMachine().getConfiguration().set(Constants.UUIDParameter, d.getUUID());
            getVirtualMachine().getConfiguration().set(Constants.CpusParameter, d.getMaxVcpus());
            getVirtualMachine().getConfiguration().set(Constants.IdParameter, d.getID());
            getVirtualMachine().getConfiguration().set(Constants.MaxMemoryParameter, d.getMaxMemory());
            getVirtualMachine().getConfiguration().set(Constants.NameParameter, d.getName());
        } catch (NumberFormatException e) {
            System.err.println("The virtualMachineID " + virtualMachineID + " is not a number");
        } catch (LibvirtException e) {
            e.getStackTrace();
        }
    }

    @Override
    public VirtualMachine getVirtualMachine(String virtualMachineName) {
        try {
            if (getVirtualMachines() != null) {
                for (VirtualMachine vm : getVirtualMachines()) {
                    if (StringUtils.equalsIgnoreCase(vm.getDomain().getName(), virtualMachineName)) {
                        return vm;
                    }
                }
            }
        } catch (LibvirtException e) {
            e.getStackTrace();
        }
        return null;
    }

    @Override
    public void migrate(int idToMigrate, String uri) {
        try {
            Connect dconn = new Connect(Constants.XEN_SSH_CONNECTION + uri + Constants.BAR, defaultAuth, 0);
            Domain d = connection.domainLookupByID(idToMigrate);
            if (d != null) {
                System.out.println("Migrating a Domain " + d.getName() + " [" + idToMigrate + "] to " + uri + " ...");
                d.migrate(dconn, 1, null, uri, 0);
                System.out.println("Domain migrated!");
            } else {
                System.out.println("Domain didn't find.");
            }
        } catch (LibvirtException e) {
            System.err.println("Error on migrate");
            e.getStackTrace();
        }
    }

    @Override
    public VirtualMachine newVMInstanceFromXMLFile(String xmlFile) {
        try {
            File f = new File(xmlFile);
            if (!f.exists()) {
                throw new IOException();
            }
            BufferedReader in = new BufferedReader(new FileReader(f));
            String str = "", out = "";
            while ((str = in.readLine()) != null) {
                out = out + str;
            }
            in.close();

            // Define a new Domain
            System.out.println("Creating a Domain...");

            Domain d = connection.domainCreateLinux(out, 0);

            System.out.println("Domain " + d.getID() + " created!");
            VirtualMachine vm = new VirtualMachine(d);
            return vm;
        } catch (IOException e) {
            System.err.println("File xml does not exist!");
        } catch (LibvirtException e) {
            e.getStackTrace();
        }
        return null;
    }

    @Override
    public VirtualMachine newVMInstance(String xmlString) {
        try {
            // Define a new Domain
            System.out.println("Creating a Domain...");

            Domain d = connection.domainCreateLinux(xmlString, 0);

            System.out.println("Domain " + d.getID() + " created!");

            VirtualMachine vm = new VirtualMachine(d);
            return vm;
        } catch (LibvirtException e) {
            e.getStackTrace();
        }
        return null;
    }

    @Override
    public void destroyVMInstance(VirtualMachine virtualMachine) {
        try {
            System.out.println("Destroying a Domain...");
            virtualMachine.getDomain().destroy();
            System.out.println("Domain destroyed!");
        } catch (LibvirtException ex) {
        }
    }

    @Override
    public void destroyVMInstance(String idMachine) {
        try {
            int idToDelete = Integer.parseInt(idMachine);

            Domain d = this.connection.domainLookupByID(idToDelete);

            if (d != null) {
                System.out.println("Destroying a Domain...");
                d.destroy();
                System.out.println("Domain " + idToDelete + " destroyed!");
            } else {
                System.out.println("Domain didn't find!");
            }
        } catch (NumberFormatException e) {
            System.err.println("The idMachine " + idMachine + " is not a number");
        } catch (LibvirtException e) {
            e.getStackTrace();
        }
    }
}
